import { UniqueObjectConfig, UniqueObjectPropertyChanged } from "../../../core/unique_class";
import Utils, { Random, Sync, Uid } from "../../../core/utils";
import FrameBuffer from "../../../prefabs/frame_buffer";
import { Character, CharacterConfig } from "../game/character";
import { GameUtils } from "../game_utils";
import CCObject, { ArrData } from "./cc_object";

const { ccclass, property } = cc._decorator;

@ccclass
export default class CCCharacter extends CCObject {
    isDead = false;
    @property(FrameBuffer)
    fb: FrameBuffer = null;

    @property([cc.Color])
    colors: cc.Color[] = [];

    @property(cc.Node)
    touch: cc.Node = null;
    @property([cc.Node])
    colorNodes: cc.Node[] = [];

    @property({ serializable: true })
    _bodyColor = cc.color();
    @property
    set bodyColor(val) {
        this._bodyColor = val;
        this.colorNodes.forEach(node => {
            node.color = val;
        });
    }
    get bodyColor() {
        return this._bodyColor;
    }
    @property(cc.Node)
    face: cc.Node = null;
    @property(cc.Animation)
    ani: cc.Animation = null;

    character: Character = null;
    protected onDestroy(): void {
        if (this.character) {
            this.character.subject.off(this);
            this.character = null;
        }
    }

    protected start(): void {
        this.fb.sprite.spriteFrame.getTexture().setPremultiplyAlpha(true);
    }
    setData(char: Character) {
        if (this.character) {
            this.character.subject.off(this);
            this.character = null;
        }
        this.character = char;

        if (!this.objUid) {
            this.objUid = Uid.getUid();
        }

        this.refresh();
        this.character.subject.on("changed", this.onChanged, this);
    }
    onChanged(m: UniqueObjectPropertyChanged) {
        this.refresh();
    }
    refresh() {
        this.face.destroyAllChildren();
        let color = this.colors[this.character.data.color];
        this.bodyColor = color;
        this.face.addChild(GameUtils.InstantiateCCGame(`eye${this.character.data.eye}`));
        this.face.addChild(GameUtils.InstantiateCCGame(`mouth${this.character.data.mouth}`));
        Utils.ChangeGroupRec(this.face.group, this.face.groupIndex, this.face);
    }
    die() {
        this.isDead = true;
        cc.tween(this.node).to(1, { opacity: 0 }).start();
    }

    state2 = "";
    walk(dv: cc.Vec2) {
        this.dv = dv;
        if (this.state2 !== "eggy_2_walk") {
            this.state2 = "eggy_2_walk";
            this.ani.playAdditive("eggy_2_walk");
        }
    }
    stop() {
        this.dv = cc.v2();
        if (this.state2 !== "eggy_2_stop") {
            this.state2 = "eggy_2_stop";
            this.ani.playAdditive("eggy_2_stop");
        }
    }
    attack() {
        this.ani.stop("eggy_attack");
        this.ani.playAdditive("eggy_attack");
    }
    grabObj: CCObject = null;
    grab(ccObj: CCObject) {
        this.grabObj = ccObj;
        this.ani.stop("eggy_grabed");
        this.ani.stop("eggy_ungrabed");
        this.ani.playAdditive("eggy_grabed");
    }
    drop() {
        this.grabObj = null;
        this.ani.stop("eggy_grabed");
        this.ani.stop("eggy_ungrabed");
        this.ani.playAdditive("eggy_ungrabed");
    }
    toArrData(): ArrData {
        let data: ArrData = super.toArrData();
        data.push(this.character.data.color);
        data.push(this.character.data.eye);
        data.push(this.character.data.mouth);
        return data;
    }
    fromArrData(data: ArrData): void {
        super.fromArrData(data);

        let char = this.character;
        if (!char) {
            char = new Character();
            let conf = new CharacterConfig();
            UniqueObjectConfig.AssignUniqueObject(char, conf);
            char.uuid = this.owner;
        }
        // let objName = data.shift();
        char.data.color = data.shift();
        char.data.eye = data.shift();
        char.data.mouth = data.shift();

        if (!this.character) {
            this.setData(char);
        }
    }

    protected update(dt: number): void {
        super.update(dt);
        if (this.grabObj) {
            this.grabObj.node.setPosition(
                this.node.position.add(cc.v3(0, 100, 0))
            )
        }
    }
};